package com.xbongbong.saas.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormEntity;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.PaySheetTypeEnum;
import com.xbongbong.paas.model.FineClueConsumptionModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.CommentUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.domain.entity.AiAssistantEntity;
import com.xbongbong.pro.domain.entity.FineClueConsumptionEntity;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.enums.RelTypeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.menu.enums.FineClueStatusEnum;
import com.xbongbong.pro.purchase.pojo.dto.PurchaseUpdateBatchDTO;
import com.xbongbong.pro.purchase.pojo.dto.PurchaseUpdateDTO;
import com.xbongbong.pro.script.pojo.dto.UpdateDataDTO;
import com.xbongbong.pro.script.pojo.vo.ScriptVO;
import com.xbongbong.pro.smartsettings.pojo.dto.AiAssistantFixDataDTO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.FineClueScriptEntity;
import com.xbongbong.saas.domain.entity.ext.CustomerEntityExt;
import com.xbongbong.saas.domain.entity.ext.PayPlanEntityExt;
import com.xbongbong.saas.domain.entity.ext.PayPlanSheetEntityExt;
import com.xbongbong.saas.domain.entity.ext.PurchaseEntityExt;
import com.xbongbong.saas.enums.SheetAloneEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.PayPlanEnum;
import com.xbongbong.saas.enums.business.PaySheetEnum;
import com.xbongbong.saas.enums.business.PurchaseEnum;
import com.xbongbong.saas.help.SaasPayPlanHelper;
import com.xbongbong.saas.model.AiAssistantModel;
import com.xbongbong.saas.model.ClueModel;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.model.PayPlanModel;
import com.xbongbong.saas.model.PayPlanSheetModel;
import com.xbongbong.saas.model.PurchaseModel;
import com.xbongbong.saas.service.PurchaseService;
import com.xbongbong.saas.service.RepairDataService;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.model.CompanyModel;
import org.apache.commons.collections4.CollectionUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * 应用模块名称<p>
 * 代码描述<p>
 * Company: 逍邦网络科技有限公司<p>
 *
 * @author chenshan
 * @version v1.0
 * @since 2020-03-05 16:11
 */
@Service("repairDataService")
public class RepairDataServiceImpl implements RepairDataService {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(RepairDataServiceImpl.class);
    @Resource
    private PayPlanModel payPlanModel;
    @Resource
    private PurchaseService purchaseService;
    @Resource
    private CompanyModel companyModel;
    @Resource
    private EsHelper esHelper;
    @Resource
    private PayPlanSheetModel payPlanSheetModel;
    @Resource
    private PurchaseModel purchaseModel;
    @Resource
    private SaasPayPlanHelper saasPayPlanHelper;
    @Resource
    private FineClueConsumptionModel fineClueConsumptionModel;
    @Resource
    private CustomerModel customerModel;
    @Resource
    private ClueModel clueModel;
    @Resource
    private AiAssistantModel aiAssistantModel;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private IndexTypeModel indexTypeModel;
    
    /**
     * 更新付款计划的数据，主要是插入坏账金额、开票金额
     *
     * @param updateDataDTO
     * @return
     * @throws XbbException
     */
    @Override
    public ScriptVO scriptPayPlanData(UpdateDataDTO updateDataDTO) throws XbbException {
        List<Long> dataIds = updateDataDTO.getDataIds();
        List<String> corpidList = updateDataDTO.getCorpidList();
        if ( CollectionsUtil.isEmpty(corpidList) ) {
            corpidList = companyModel.getCorpidList();
        }
        int i = 1;
        Long startTime = DateTimeUtil.getInt();
        for ( String corpid : corpidList ) {
            int x = corpidList.size() - i;
            Long idGte = 0L;
            int pageSize = 1000;
            LOGGER.info("当前是第" + i + "家公司,还有" + x + "家是公司需要刷");
            i++;
            try {
                Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put(ParameterConstant.CORPID, corpid);
                param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
                if ( Objects.nonNull(updateDataDTO.getStartTime()) ) {
                    CommentUtil.addToMap(param, "startTime", updateDataDTO.getStartTime());
                }
                if ( Objects.nonNull(updateDataDTO.getEndTime()) ) {
                    CommentUtil.addToMap(param, "endTime", updateDataDTO.getEndTime());
                }
                int j = 0;
                while (true) {
                    LOGGER.info("当前是" + j++ + "页");
                    param.put("pageSize", pageSize);
                    param.put("orderByStr", "id asc");
                    param.put("idGte", idGte);
                    List<PayPlanEntityExt> payPlanList = payPlanModel.findEntitys(param);
                    if ( payPlanList.isEmpty() ) {
                        break;
                    }
                    List<UpdateDataEntity> list = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    JSONObject data = new JSONObject();
                    data.put(PayPlanEnum.INVOICE_AMOUNT.getAttr(), 0D);
                    data.put(PayPlanEnum.BAD_AMOUNT.getAttr(), 0D);
                    payPlanList.forEach(item -> {
                        list.add(ExplainUtil.getUpdateData(item.getId(), data, corpid));
                    });
                    PayPlanEntityExt payPlanEntityExt = payPlanList.get(payPlanList.size()-1);
                    if ( Objects.nonNull(payPlanEntityExt) ) {
                        idGte = payPlanEntityExt.getId();
                    }
                    if ( CollectionsUtil.isNotEmpty(list) ) {
                        payPlanModel.updateBatch(list, corpid);
                    }
                }
            } catch (XbbException e) {
                LOGGER.error("公司编号为:" + corpid + "更新失败,失败理由是", e);
            } catch (Exception e) {
                LOGGER.error("公司编号为:" + corpid + "更新失败,失败理由是", e);
            }
        }
        LOGGER.info("---更新付款计划的数据，主要是插入坏账金额、开票金额脚本结束");
        Long endTime = DateTimeUtil.getInt();
        Long consumeTime = endTime - startTime;
        LOGGER.info("---耗时为："+ consumeTime);
        return null;
    }

    @Override
    public ScriptVO payPlanFinishAmount(UpdateDataDTO updateDataDTO) throws XbbException {
        String corpid = updateDataDTO.getCorpid();
        if (StringUtil.isEmpty(corpid)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100002, SystemErrorCodeEnum.API_ERROR_100002.getMsg());
        }
        Long startTime = DateTimeUtil.getInt();
        try {
            List<Long> dataIds = updateDataDTO.getDataIds();
            Map<String, Object> planParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            planParam.put("corpid", corpid);
            planParam.put("del", 0);
            if (CollectionUtils.isNotEmpty(dataIds)) {
                planParam.put("ids", dataIds);
            }
            Integer total = payPlanModel.getEntitysCount(planParam);
            BoolQueryBuilder sheetQueryBuilder = getPaySheetBoolQueryBuilder(corpid);
            Integer start = 0;
            //每次查询100条
            Integer pageNum = 100;
            Long idGte = 0L;
            planParam.put("start", start);
            planParam.put("pageNum", pageNum);
            planParam.put("orderByStr", "id asc");
            int dealCount = 0;
            while (true) {
                planParam.put("idGte", idGte);
                List<PayPlanEntityExt> planList = payPlanModel.findEntitys(planParam);
                dealCount += planList.size();
                if (planList.size() == 0) {
                    break;
                }
                idGte = planList.get(planList.size() - 1).getId();
                List<Long> planIdIn = planList.stream().map(p -> p.getId()).collect(Collectors.toList());
                //父款计划id-已付总额
                Map<Long, Double> pidFinishMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                //父款计划id-坏账总额
                Map<Long, Double> pidBadMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                //遍历付款单，汇总其已付、坏账
                sumFinishAndBad(planIdIn, sheetQueryBuilder, pidFinishMap, pidBadMap, PaySheetEnum.PAY_PLAN);
                List<UpdateDataEntity> list = new ArrayList<>(planList.size());
                for (PayPlanEntityExt entityExt : planList) {
                    JSONObject data = JsonHelperUtil.getJSONObject(entityExt.getData());
                    Double planAmount = data.getDoubleValue(PayPlanEnum.AMOUNT.getAttr());
                    Double finishedMoney = data.getDouble(PayPlanEnum.REAL_AMOUNT.getAttr());
                    Double unFinishedMoney = data.getDouble(PayPlanEnum.UN_AMOUNT.getAttr());
                    String planStatus = data.getString(PayPlanEnum.STATUS.getAttr());
                    Double badMoney = data.getDouble(PayPlanEnum.BAD_AMOUNT.getAttr());
                    //付款计划的总已付金额（已经处理过红冲）
                    Double finishAmount = pidFinishMap.getOrDefault(entityExt.getId(), 0D);
                    //付款计划的总坏账金额
                    Double badAmount = pidBadMap.getOrDefault(entityExt.getId(), 0D);
                    //未收款金额 = 付款计划金额 - ( 已付款金额(红冲的已经处理在已付内)+坏账金额 ) = 付款计划金额 - 已付款金额 - 坏账金额
                    Double rightUnFinished = Arith.sub(Arith.sub(planAmount, finishAmount), badAmount);
                    JSONObject updateData = new JSONObject();
                    if (!Objects.equals(finishedMoney, finishAmount)) {
                        updateData.put(PayPlanEnum.REAL_AMOUNT.getAttr(), finishAmount);
                    }
                    if (!Objects.equals(unFinishedMoney, rightUnFinished)) {
                        updateData.put(PayPlanEnum.UN_AMOUNT.getAttr(), rightUnFinished);
                    }
                    if (!Objects.equals(badMoney, badAmount)) {
                        updateData.put(PayPlanEnum.BAD_AMOUNT.getAttr(), badAmount);
                    }
                    String rightPlanStatus = saasPayPlanHelper.handleStatus(planAmount, rightUnFinished, badAmount);
                    if (!Objects.equals(planStatus, rightPlanStatus)) {
                        updateData.put(PayPlanEnum.STATUS.getAttr(), rightPlanStatus);
                    }
                    if (!updateData.isEmpty()) {
                        list.add(ExplainUtil.getUpdateData(entityExt.getId(), updateData, corpid));
                    }
                }
                if ( CollectionsUtil.isNotEmpty(list) ) {
                    payPlanModel.updateBatch(list, corpid);
                }
                LOGGER.warn("处理进度：已处理" + dealCount + "/" + total);
            }
        } catch (XbbException e) {
            LOGGER.error("公司编号为:" + corpid + "更新失败,失败理由是", e);
        } catch (Exception e) {
            LOGGER.error("公司编号为:" + corpid + "更新失败,失败理由是", e);
        }
        LOGGER.warn("---修正付款计划的 已付、未付、坏账、付款状态 脚本结束");
        Long consumeTime = DateTimeUtil.getInt() - startTime;
        LOGGER.warn("---耗时为："+ consumeTime);
        return null;
    }

    /**
     * 更新采购合同的数据，主要是插入
     * 坏账金额=0、实付金额=根据付款单计算金额、未付金额=采购合同金额-实付金额、付款比例=实付金额/采购合同金额、开票金额=0、未开票金额=0
     *
     * @param updateDataDTO
     * @return
     * @throws XbbException
     */
    @Override
    public ScriptVO scriptPurchaseData(UpdateDataDTO updateDataDTO) throws XbbException {
        List<String> corpidList = updateDataDTO.getCorpidList();
        if ( CollectionsUtil.isEmpty(corpidList) ) {
            corpidList = companyModel.getCorpidList();
        }
        int i = 1;
        Long startTime = DateTimeUtil.getInt();
        LOGGER.info("---共有"+corpidList.size()+"家是公司需要刷");
        for ( String corpid : corpidList ) {
            int x = corpidList.size() - i;
            Long idGte = 0L;
            int pageSize = 500;
            LOGGER.info("当前是第" + i + "家公司,"+corpid+"还有" + x + "家是公司需要刷");
            i++;
            try {
                if ( Objects.nonNull(updateDataDTO.getNoInit()) && Objects.equals(updateDataDTO.getNoInit(),1) ) {
                    Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    param.put(ParameterConstant.CORPID, corpid);
                    param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
                    if ( Objects.nonNull(updateDataDTO.getStartTime()) ) {
                        CommentUtil.addToMap(param, "startTime", updateDataDTO.getStartTime());
                    }
                    if ( Objects.nonNull(updateDataDTO.getEndTime()) ) {
                        CommentUtil.addToMap(param, "endTime", updateDataDTO.getEndTime());
                    }
                    int j = 0;
                    while (true) {
                        LOGGER.info("当前是" + j++ + "页");
                        param.put("pageSize", pageSize);
                        param.put("orderByStr", "id asc");
                        param.put("idGte", idGte);
                        List<PurchaseEntityExt> purchaseList = purchaseModel.findEntitys(param);
                        if ( purchaseList.isEmpty() ) {
                            break;
                        }
                        List<UpdateDataEntity> list = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        JSONObject data = new JSONObject();
                        data.put(PurchaseEnum.BAD_AMOUNT.getAttr(), 0D);
                        data.put(PurchaseEnum.FINISH_AMOUNT.getAttr(), 0D);
                        data.put(PurchaseEnum.RECEINE_PERCENT.getAttr(), 0);
                        data.put(PurchaseEnum.INVOICE_AMOUNT.getAttr(), 0D);
                        for ( PurchaseEntityExt item : purchaseList ) {
                            Double totalMoney = FastJsonHelper.getDoubleOrDefaultFromFormData(item.getData(),PurchaseEnum.TOTAL_MONEY.getAttr(),0D);
                            data.put(PurchaseEnum.UN_FINISH_AMOUNT.getAttr(), totalMoney);
                            data.put(PurchaseEnum.UN_INVOICE_AMOUNT.getAttr(), totalMoney);
                            list.add(ExplainUtil.getUpdateData(item.getId(), data, corpid));
                        }
                        PurchaseEntityExt payPlanEntityExt = purchaseList.get(purchaseList.size()-1);
                        if ( Objects.nonNull(payPlanEntityExt) ) {
                            idGte = payPlanEntityExt.getId();
                        }
                        if ( CollectionsUtil.isNotEmpty(list) ) {
                            purchaseModel.updateBatch(list, corpid,false);
                        }
                    }
                } else {
                    Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    params.put("corpid", corpid);
                    params.put("del", 0);
                    params.put("condition", " and JSON_EXTRACT(data, '$." + PaySheetEnum.PAY_SHEET_TYPE.getAttr() + "') =  '1'");
    
                    int j = 0;
                    while (true) {
                        LOGGER.info("当前是" + j++ + "页,==============idGte:" + idGte );
                        params.put("pageSize", pageSize);
                        params.put("orderByStr", "id asc");
                        params.put("idGte", idGte);
                        List<PayPlanSheetEntityExt> payPlanSheetList = payPlanSheetModel.findEntitys(params);
                        if ( payPlanSheetList.isEmpty() ) {
                            break;
                        }
                        PayPlanSheetEntityExt payPlanEntityExt = payPlanSheetList.get(payPlanSheetList.size()-1);
                        if ( Objects.nonNull(payPlanEntityExt) ) {
                            idGte = payPlanEntityExt.getId();
                        }
                        Map<Long, Double> purchaseIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        Double totalAmount = 0D;
                        Set<Long> purchaseIdSet = new HashSet<>(payPlanSheetList.size());
                        for ( PayPlanSheetEntityExt payPlanSheetEntityExt : payPlanSheetList ) {
                            JSONObject dataList = payPlanSheetEntityExt.getData();
                            JSONArray purchaseIdArr = FastJsonHelper.getJsonArrFromFormData(dataList, PaySheetEnum.LINK_PURCHASE.getAttr());
                            Double amount = FastJsonHelper.getDoubleOrDefaultFromFormData(dataList, PaySheetEnum.AMOUNT.getAttr(), 0D);
                            for ( Object purchaseIdObj : purchaseIdArr ) {
                                Long purchaseId = Long.valueOf(purchaseIdObj.toString());
                                totalAmount = purchaseIdToAmount.getOrDefault(purchaseId,0D);
                                totalAmount = totalAmount + amount;
                                purchaseIdToAmount.put(purchaseId, totalAmount);
                                purchaseIdSet.add(purchaseId);
                            }
                        }
                        
                        if ( CollectionsUtil.isNotEmpty(purchaseIdSet) ) {
                            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                            PurchaseUpdateBatchDTO purchaseUpdateBatchDTO = new PurchaseUpdateBatchDTO();
                            purchaseUpdateBatchDTO.setCorpid(corpid);
                            List<PurchaseUpdateDTO> purchaseList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                            param.put("corpid", corpid);
                            param.put("idIn", purchaseIdSet);
                            param.put("del", 0);
                            List<PurchaseEntityExt> payPlanList = purchaseModel.findEntitys(param);
                            LOGGER.info("合同编号："+purchaseIdSet);
                            for ( PurchaseEntityExt item : payPlanList ) {
                                PurchaseUpdateDTO purchaseUpdateDTO = new PurchaseUpdateDTO();
                                JSONObject data = item.getData();
                                Long id = item.getId();
                                Double finishAmount = purchaseIdToAmount.get(id);
                                Double readyFinishAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, PurchaseEnum.FINISH_AMOUNT.getAttr(), 0D);
                                Double totalFinishAmount = Arith.add(readyFinishAmount,finishAmount);
                                Double totalPurchaseAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, PurchaseEnum.TOTAL_MONEY.getAttr(), 0D);
                                Double unFinishAmount = Arith.sub(totalPurchaseAmount, totalFinishAmount);
                                Double receivePercent = 0D;
                                if (!Objects.equals(totalPurchaseAmount,0D)) {
                                    receivePercent = Arith.div(totalFinishAmount, totalPurchaseAmount, 2);
                                }
                                
                                JSONObject newData = new JSONObject();
                                newData.put(PurchaseEnum.FINISH_AMOUNT.getAttr(), totalFinishAmount);
                                newData.put(PurchaseEnum.UN_FINISH_AMOUNT.getAttr(), unFinishAmount);
                                newData.put(PurchaseEnum.RECEINE_PERCENT.getAttr(), receivePercent);
                                purchaseUpdateDTO.setId(id);
                                purchaseUpdateDTO.setData(newData);
                                purchaseUpdateDTO.setUpdateTime(item.getUpdateTime());
                                purchaseList.add(purchaseUpdateDTO);
                            }
                            if (CollectionsUtil.isNotEmpty(purchaseList)) {
                                purchaseUpdateBatchDTO.setPurchaseList(purchaseList);
                                purchaseService.updateBatch(purchaseUpdateBatchDTO, false, false);
                            }
                        }
                    }
                }
            } catch (XbbException e) {
                LOGGER.error("公司编号为:" + corpid + "更新失败,失败理由是", e);
            } catch (Exception e) {
                LOGGER.error("公司编号为:" + corpid + "更新失败,失败理由是", e);
            }
        }
        LOGGER.info("---更新采购合同的数据，主要是插入坏账金额=0、实付金额=根据付款单计算金额、未付金额=采购合同金额-实付金额、付款比例=实付金额/采购合同金额、开票金额=0、未开票金额=0脚本结束");
        Long endTime = DateTimeUtil.getInt();
        Long consumeTime = endTime - startTime;
        LOGGER.info("---耗时为："+ consumeTime);
        return null;
    }

    @Override
    public ScriptVO purchaseFinishAmount(UpdateDataDTO updateDataDTO) throws XbbException {
        String corpid = updateDataDTO.getCorpid();
        if (StringUtil.isEmpty(corpid)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100002, SystemErrorCodeEnum.API_ERROR_100002.getMsg());
        }
        Long startTime = DateTimeUtil.getInt();
        try {
            List<Long> dataIds = updateDataDTO.getDataIds();
            Map<String, Object> purchaseParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            purchaseParam.put("corpid", corpid);
            purchaseParam.put("del", 0);
            if (CollectionUtils.isNotEmpty(dataIds)) {
                purchaseParam.put("idIn", dataIds);
            }
            purchaseParam.put("flowStatusIn", Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType()));
            Integer total = purchaseModel.getEntitysCount(purchaseParam);
            BoolQueryBuilder sheetQueryBuilder = getPaySheetBoolQueryBuilder(corpid);
            Integer start = 0;
            //每次查询100条
            Integer pageNum = 100;
            Long idGte = 0L;
            purchaseParam.put("start", start);
            purchaseParam.put("pageNum", pageNum);
            purchaseParam.put("orderByStr", "id asc");
            int dealCount = 0;
            while (true) {
                purchaseParam.put("idGte", idGte);
                List<PurchaseEntityExt> purchaseList = purchaseModel.findEntitys(purchaseParam);
                dealCount += purchaseList.size();
                if (purchaseList.size() == 0) {
                    break;
                }
                idGte = purchaseList.get(purchaseList.size() - 1).getId();
                List<Long> purchaseIdIn = purchaseList.stream().map(p -> p.getId()).collect(Collectors.toList());
                //采购合同id-已付总额
                Map<Long, Double> pidFinishMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                //采购合同id-坏账总额
                Map<Long, Double> pidBadMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                //遍历付款单，汇总其已付、坏账
                sumFinishAndBad(purchaseIdIn, sheetQueryBuilder, pidFinishMap, pidBadMap, PaySheetEnum.LINK_PURCHASE);
                List<UpdateDataEntity> list = new ArrayList<>(purchaseList.size());
                for (PurchaseEntityExt entityExt : purchaseList) {
                    JSONObject data = JsonHelperUtil.getJSONObject(entityExt.getData());
                    Double totalMoney = data.getDoubleValue(PurchaseEnum.TOTAL_MONEY.getAttr());
                    Double finishedMoney = data.getDouble(PurchaseEnum.FINISH_AMOUNT.getAttr());
                    Double unFinishedMoney = data.getDouble(PurchaseEnum.UN_FINISH_AMOUNT.getAttr());
                    Double payPercent = data.getDouble(PurchaseEnum.RECEINE_PERCENT.getAttr());
                    Double badMoney = data.getDouble(PurchaseEnum.BAD_AMOUNT.getAttr());
                    //采购合同的总已付金额（已经处理过红冲）
                    Double finishAmount = pidFinishMap.getOrDefault(entityExt.getId(), 0D);
                    //采购合同的总坏账金额
                    Double badAmount = pidBadMap.getOrDefault(entityExt.getId(), 0D);
                    //未收款金额 = 采购合同金额 - ( 已付款金额(红冲的已经处理在已付内)+坏账金额 ) = 采购合同金额 - 已付款金额 - 坏账金额
                    Double rightUnFinished = Arith.sub(Arith.sub(totalMoney, finishAmount), badAmount);
                    JSONObject updateData = new JSONObject();
                    // 正确的合同收款比率
                    Double rightPayPercent = 1D;
                    if (Double.compare(totalMoney, 0) != 0) {
                        rightPayPercent = Arith.div(finishAmount, totalMoney);
                    }
                    if (!Objects.equals(finishedMoney, finishAmount)) {
                        updateData.put(PurchaseEnum.FINISH_AMOUNT.getAttr(), finishAmount);
                    }
                    if (!Objects.equals(unFinishedMoney, rightUnFinished)) {
                        updateData.put(PurchaseEnum.UN_FINISH_AMOUNT.getAttr(), rightUnFinished);
                    }
                    if (!Objects.equals(payPercent, rightPayPercent)) {
                        updateData.put(PurchaseEnum.RECEINE_PERCENT.getAttr(), rightPayPercent);
                    }
                    if (!Objects.equals(badMoney, badAmount)) {
                        updateData.put(PurchaseEnum.BAD_AMOUNT.getAttr(), badAmount);
                    }
                    if (!updateData.isEmpty()) {
                        list.add(ExplainUtil.getUpdateData(entityExt.getId(), updateData, corpid));
                    }
                }
                if ( CollectionsUtil.isNotEmpty(list) ) {
                    purchaseModel.updateBatch(list, corpid,false);
                }
                LOGGER.warn("处理进度：已处理" + dealCount + "/" + total);
            }
        } catch (XbbException e) {
            LOGGER.error("公司编号为:" + corpid + "更新失败,失败理由是", e);
        } catch (Exception e) {
            LOGGER.error("公司编号为:" + corpid + "更新失败,失败理由是", e);
        }
        LOGGER.warn("---修正采购合同的 已付、未付、坏账、付款比例 脚本结束");
        Long consumeTime = DateTimeUtil.getInt() - startTime;
        LOGGER.warn("---耗时为："+ consumeTime);
        return null;
    }

    /**
     * 查询付款单的基本条件
     * @param corpid
     * @return org.elasticsearch.index.query.BoolQueryBuilder
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private BoolQueryBuilder getPaySheetBoolQueryBuilder(String corpid) {
        BoolQueryBuilder sheetQueryBuilder = boolQuery();
        sheetQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        sheetQueryBuilder.filter(termQuery("del", 0));
        //限制alone：只读取子单或无子的单据，不读合并付款的父单
        sheetQueryBuilder.filter(termsQuery(FieldTypeEnum.SHEET_ALONE.getAlias(), SheetAloneEnum.getNotParentCodeList()));
        //无需审批和通过
        sheetQueryBuilder.filter(termsQuery("flowStatus", FlowStatusEnum.getStatisticType()));
        //读取无预付款、红冲预付款余额类型的付款单，因为这两种不会影响采购合同/付款计划的已付未付
        sheetQueryBuilder.filter(termsQuery(PaySheetEnum.getEsAttr4Keyword(PaySheetEnum.PAY_SHEET_TYPE), PaySheetTypeEnum.getCodeList4NoPre()));
        return sheetQueryBuilder;
    }

    /**
     * 遍历付款单，把同个采购合同/付款计划的已付(红冲)，坏账汇总到一个map
     * @param linkIdIn 关联采购合同/付款计划id集合
     * @param sheetQueryBuilder 付款单基础查询条件
     * @param pidFinishMap 采购合同/付款计划id - 总已付金额(已经处理红冲部分) 对应关系map
     * @param pidBadMap 采购合同/付款计划id - 总坏账金额 对应关系map
     * @param linkEnum 关联采购合同、或关联付款计划
     * @throws
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void sumFinishAndBad(List<Long> linkIdIn, BoolQueryBuilder sheetQueryBuilder, Map<Long, Double> pidFinishMap, Map<Long, Double> pidBadMap, PaySheetEnum linkEnum) throws XbbException {
        String attrLink = PaySheetEnum.getEsAttr4Keyword(linkEnum);
        esHelper.removeSearchCondition(sheetQueryBuilder, attrLink);
        sheetQueryBuilder.filter(termsQuery(attrLink, linkIdIn));
        List<PayPlanSheetEntityExt> paySheetEntityExts = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET, sheetQueryBuilder, PayPlanSheetEntityExt.class, null);
        for (PayPlanSheetEntityExt paySheetEntityExt : paySheetEntityExts) {
            JSONObject data = JsonHelperUtil.getJSONObject(paySheetEntityExt.getData());
            double amount = data.getDoubleValue(PaySheetEnum.AMOUNT.getAttr());
            //关联采购合同or关联付款计划(数组格式)：读取的都是无明细或子单，肯定是size为1的数组
            Long planId = data.getJSONArray(linkEnum.getAttr()).getLong(BasicConstant.ZERO);
            String sheetType = data.getString(PaySheetEnum.PAY_SHEET_TYPE.getAttr());
            PaySheetTypeEnum paySheetTypeEnum = PaySheetTypeEnum.getByCode(sheetType);
            switch (paySheetTypeEnum) {
                case WRITE_OFF_PAY:
                case RED_WRITE_OFF_PAY:
                case RED_WRITE_OFF_PREPAY:
                    //红冲的数据库存的是负数，因此也是加
                    amount += pidFinishMap.getOrDefault(planId, 0D);
                    pidFinishMap.put(planId, amount);
                    break;
                case WRITE_OFF_PREPAY:
                    amount = data.getDoubleValue(PaySheetEnum.WRITE_OFF_AMOUNT.getAttr());
                    amount += pidFinishMap.getOrDefault(planId, 0D);
                    pidFinishMap.put(planId, amount);
                    break;
                case BAD_PAY:
                    amount += pidBadMap.getOrDefault(planId, 0D);
                    pidBadMap.put(planId, amount);
                    break;
                default:
                    break;
            }
        }
    }

    @Override
    public ScriptVO fixFineCluePid(UpdateDataDTO updateDataDTO) throws XbbException {
        ScriptVO scriptVO = new ScriptVO();
        long start = DateTimeUtil.getInt();
        List<String> corpidList = updateDataDTO.getCorpidList();
        if (CollectionsUtil.isEmpty(corpidList)) {
            // 查询搜客公司
            corpidList = fineClueConsumptionModel.getCorpidList();
        }

        Integer index = 1;
        for (String corpid : corpidList) {
            LOGGER.warn(index + "/" + corpidList.size());
            // 查询没有关联数据id的数据
            List<FineClueConsumptionEntity> consumptionList = fineClueConsumptionModel.getPidsByDataIdEmpty(corpid);
            if (CollectionsUtil.isEmpty(consumptionList)) {
                continue;
            }
            List<String> pids = new ArrayList<>();
            Map<String, FineClueConsumptionEntity> consumptionEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (FineClueConsumptionEntity consumptionEntity : consumptionList) {
                pids.add(consumptionEntity.getPid());
                consumptionEntityMap.put(consumptionEntity.getPid(), consumptionEntity);
            }
            List<FineClueScriptEntity> customerList = new ArrayList<>();
            List<FineClueScriptEntity> clueList = new ArrayList<>();
            List<FineClueConsumptionEntity> updateList = new ArrayList<>();
            List<String> updatePids = new ArrayList<>();
            // 查询客户 && 销售线索，有对应数据添加绑定关系
            int count = pids.size();
            int page = 0;
            int pageNum = 1000;
            for (; page <= count; page = page + pageNum) {
                int endIndex = Math.min((page + pageNum), count);
                List<String> subPids = pids.subList(page, endIndex);

                List<FineClueScriptEntity> list = customerModel.getListByPids(corpid, subPids);
                List<FineClueScriptEntity> list1 = clueModel.getListByPids(corpid, subPids);
                if (CollectionsUtil.isNotEmpty(list)) {
                    customerList.addAll(list);
                }
                if (CollectionsUtil.isNotEmpty(list1)) {
                    clueList.addAll(list1);
                }
            }
            if (CollectionsUtil.isNotEmpty(customerList)) {
                for (FineClueScriptEntity fineClueScriptEntity : customerList) {
                    updatePids.add(fineClueScriptEntity.getPid());
                    FineClueConsumptionEntity fineClueConsumptionEntity = consumptionEntityMap.get(fineClueScriptEntity.getPid());
                    fineClueConsumptionEntity.setBusinessType(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());
                    fineClueConsumptionEntity.setFormId(fineClueScriptEntity.getFormId());
                    fineClueConsumptionEntity.setDataId(fineClueScriptEntity.getId());
                    fineClueConsumptionEntity.setStatus(FineClueStatusEnum.UNLOCK.getCode());

                    updateList.add(fineClueConsumptionEntity);
                }
            }
            if (CollectionsUtil.isNotEmpty(clueList)) {
                for (FineClueScriptEntity fineClueScriptEntity : clueList) {
                    // 客户已有pid销售线索不更新
                    if (updatePids.contains(fineClueScriptEntity.getPid())) {
                       continue;
                    }
                    FineClueConsumptionEntity fineClueConsumptionEntity = consumptionEntityMap.get(fineClueScriptEntity.getPid());
                    fineClueConsumptionEntity.setBusinessType(XbbRefTypeEnum.CLUE.getCode());
                    fineClueConsumptionEntity.setFormId(fineClueScriptEntity.getFormId());
                    fineClueConsumptionEntity.setDataId(fineClueScriptEntity.getId());
                    fineClueConsumptionEntity.setStatus(FineClueStatusEnum.UNLOCK.getCode());

                    updateList.add(fineClueConsumptionEntity);
                }
            }
            if (CollectionsUtil.isNotEmpty(updateList)) {
                fineClueConsumptionModel.updateBatch(updateList, corpid);
            }
        }
        String s = "花费时间：" + ((DateTimeUtil.getInt() - start) / 60) + "分";
        scriptVO.setMsg(s);
        LOGGER.warn(s);
        return scriptVO;

    }

    @Override
    public ScriptVO fixMenuId(AiAssistantFixDataDTO aiAssistantFixDataDTO) throws XbbException {
        ScriptVO scriptVO = new ScriptVO();
        long start = DateTimeUtil.getInt();
        List<String> corpidList = aiAssistantFixDataDTO.getCorpidList();
        if (CollectionsUtil.isEmpty(corpidList)) {
            // 查询智能助手公司
            corpidList = aiAssistantModel.getCorpidList();
        }

        List<AiAssistantEntity> updateList = new ArrayList<>();
        Set<Long> formIdIn = new HashSet<>();
        // 查询参数
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
        Integer index = 1;
        for (String corpid : corpidList) {
            LOGGER.warn(index + "/" + corpidList.size());
            index++;
            // 查询没有关联数据id的数据
            param.put(StringConstant.CORPID, corpid);
            List<AiAssistantEntity> aiAssistantList = aiAssistantModel.findEntitys(param);
            if (CollectionsUtil.isEmpty(aiAssistantList)) {
                continue;
            }
            updateList.clear();
            formIdIn.clear();
            for (AiAssistantEntity aiAssistantEntity : aiAssistantList) {
                formIdIn.add(aiAssistantEntity.getFormId());
                if (Objects.isNull(aiAssistantEntity.getMenuId()) || Objects.equals(aiAssistantEntity.getMenuId(), BasicConstant.ZERO_LONG)) {
                    updateList.add(aiAssistantEntity);
                }
            }
            if (CollectionsUtil.isEmpty(updateList)) {
                continue;
            }

            // 查询表单对应的menuId
            Map<String, Object> queryFormParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            queryFormParam.put(StringConstant.CORPID, corpid);
            queryFormParam.put("idIn", formIdIn);
            queryFormParam.put(StringConstant.COLUMNS, "id, menu_id");
            List<PaasFormEntity> paasFormList = paasFormModel.findEntity(queryFormParam);
            if (CollectionsUtil.isEmpty(paasFormList)) {
                continue;
            }
            Map<Long, Long> formIdMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            paasFormList.forEach(item -> formIdMap.put(item.getId(), item.getMenuId()));
            for (AiAssistantEntity aiAssistantEntity : updateList) {
                aiAssistantEntity.setMenuId(formIdMap.get(aiAssistantEntity.getFormId()));
            }

            aiAssistantModel.updateBatch(updateList, corpid);
        }
        String s = "花费时间：" + ((DateTimeUtil.getInt() - start) / 60) + "分";
        scriptVO.setMsg(s);
        LOGGER.warn(s);
        return scriptVO;
    }

    @Override
    public ScriptVO fixCustomerDataForXbb(UpdateDataDTO updateDataDTO) throws XbbException {
        ScriptVO scriptVO = new ScriptVO();
        String corpid = "dinge3fa697f86d461d2";
        Long formId = 572924L;
        Long endDate = 1577808000L;
        String attr = "text_38";
        String endDateAttr = "date_8";
        List<Object> endDateList = new ArrayList<>();
        endDateList.add(endDate);
        IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(corpid, XbbRefTypeEnum.CUSTOMER_STATEMENT.getCode(), SaasMarkEnum.SAAS.getCode());
        //排序：id asc
        List<SortBuilder> sortBuilderList = Arrays.asList(new FieldSortBuilder(new FieldSortBuilder(BasicConstant.ID).order(SortOrder.ASC)));
        //限制返回值
        List<String> fieldList = Arrays.asList("data." + attr,"dataId");
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,customerIndex.getType()));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL,BasicConstant.ZERO));
        boolQueryBuilder.filter(termQuery("formId",formId));
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.PASS.getType(), FlowStatusEnum.NOT_NEED_APPROVAL.getType())));
        boolQueryBuilder.filter(termQuery(CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.IS_PUBLIC),BasicConstant.ZERO));
        List<ConditionsEntityExt> conditionList = new ArrayList<>();
        ConditionsEntityExt conditionsEntityExt = new ConditionsEntityExt();
        conditionsEntityExt.setAttr(attr);
        conditionsEntityExt.setFieldType(FieldTypeEnum.TEXT.getType());
        conditionsEntityExt.setSymbol(ConditionEnum.NOEMPTY.getSymbol());
        ConditionsEntityExt dateConditon = new ConditionsEntityExt();
        dateConditon.setAttr(endDateAttr);
        dateConditon.setFieldType(FieldTypeEnum.DATETIME.getType());
        dateConditon.setSymbol(ConditionEnum.GREATEREQUAL.getSymbol());
        dateConditon.setValue(endDateList);
        conditionList.add(conditionsEntityExt);
        conditionList.add(dateConditon);
        EsUtil.parseCondition(boolQueryBuilder,conditionList, RelTypeEnum.AND.getAlias(), corpid,XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());
        int page = 1;
        int pageSize = 1000;
        while (true){
            try {
                XbbAggregatedPage<CustomerEntityExt> xbbAggregatedPage = esHelper.findByPage(customerIndex, boolQueryBuilder, CustomerEntityExt.class, fieldList, page, pageSize, sortBuilderList);
                List<CustomerEntityExt> content = xbbAggregatedPage.getContent();
                if(CollectionsUtil.isEmpty(content)){
                    break;
                }
                List<UpdateDataEntity> updateDataEntityList = new ArrayList<>();
                for(CustomerEntityExt customer: content){
                    JSONObject newData = new JSONObject();
                    JSONObject data = customer.getData();
                    String value = FastJsonHelper.getStringOrDefault(data, attr, "");
                    newData.put(attr,value);
                    UpdateDataEntity updateData = ExplainUtil.getUpdateData(customer.getDataId(), newData, corpid);
                    updateDataEntityList.add(updateData);
                }
                if(CollectionsUtil.isNotEmpty(updateDataEntityList)){
                    customerModel.updateBatch(updateDataEntityList,corpid);
                }
                LOGGER.warn("第{}页处理完成,每页{}条数据",page,pageSize);
                page++;
            }catch (XbbException e){
                LOGGER.error("es查询出错,客户更新出错",e);
                page++;
            }
        }
        scriptVO.setMsg("success");
        return scriptVO;
    }
}
